﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;

namespace SysSU.JSONRPC
{
    public class JSONRPC2Notification : JSONRPC2Message
    {
        private string method;
        private object parameters;
        private JSONRPC2ParamsType paramsType;

        public string Method
        {
            get { return method; }
            set
            {
                if (value == null) throw new ArgumentException("Invalid method name.");
                method = value;
            }
        }

        public object Parameters
        {
            get { return parameters; }
            set
            {
                if (value == null) 
                {
                    paramsType = JSONRPC2ParamsType.NO_PARAMS;
                } 
                else if (value is JObject) 
                {
                    paramsType = JSONRPC2ParamsType.ARRAY;
                } 
                else if (value is JArray) 
                {
                    paramsType = JSONRPC2ParamsType.OBJECT;
                } 
                else 
                {
                    throw new ArgumentException(
                        "The notification parameters must be of type List, Map or null");
                }

                parameters = value;
            }
        }

        public static new JSONRPC2Notification Parse(string jsonString) 
        {
            var json = JSONRPC2Message.ParseJSONObject(jsonString);

            ensureVersion2(json["jsonrpc"], jsonString);

            var method = json["method"];

            if (method == null) 
            {
                throw new JSONRPC2InvalidMessageException(
                    "Invalid JSON-RPC 2.0 notification: Method name missing", jsonString);
            } 
            else if (!(method is string))
            {
                throw new JSONRPC2InvalidMessageException(
                    "Invalid JSON-RPC 2.0 notification: Method name not a JSON string", jsonString);
            } 
            else if ((method as string).Length == 0) 
            {
                throw new JSONRPC2InvalidMessageException(
                    "Invalid JSON-RPC 2.0 notification: Method name is an empty string", jsonString);
            }

            var parametres = json["params"];

            if (parametres == null) 
            {
                return new JSONRPC2Notification() { Method = method as string };
            }
            else if (parametres is JObject || parametres is JArray) 
            {
                return new JSONRPC2Notification() { Method = method as string, Parameters = parametres };
            } 
            else 
            {
                throw new JSONRPC2InvalidMessageException(
                    "Invalid JSON-RPC 2.0 notification: Method parameters have unexpected JSON type",
                    jsonString);
            }
        }

        public override JObject ToJSON()
        {
            JObject req = new JObject();

            req["method"] = Method;
            if (Parameters != null && paramsType != JSONRPC2ParamsType.NO_PARAMS) 
            {
                req["params"] = JObject.Parse(JsonConvert.SerializeObject(Parameters));
            }
            req["jsonrpc"] = "2.0";

            return req;
        }
    }
}
